﻿Imports Npgsql


Public Class XBRL
    Public Shared ReadOnly Property connstr As String
        Get
            Return "Server=public.xbrl.us;Port=5432;Database=edgar_db;User ID=" & My.Settings.userName & ";Password=" & My.Settings.password & ";CommandTimeout=1000;"
        End Get
    End Property

    Public Shared ReadOnly Property tables As sqlTables
        Get
            Dim l As New sqlTables

            l.Add(New accession())
            l.Add(New accession_document_association())
            l.Add(New accession_timestamp())
            l.Add(New attribute_value())
            l.Add(New context())
            l.Add(New context_aug())
            l.Add(New context_dimension())
            l.Add(New custom_arcrole_type())
            l.Add(New custom_arcrole_used_on())
            l.Add(New custom_role_type())
            l.Add(New custom_role_used_on())
            l.Add(New document())
            l.Add(New element())
            l.Add(New element_attribute_value_association())
            l.Add(New entity())
            l.Add(New enumeration_arcrole_cycles_allowed())
            l.Add(New enumeration_element_balance())
            l.Add(New enumeration_element_period_type())
            l.Add(New enumeration_unit_measure_location())
            l.Add(New fact())
            l.Add(New fact_aug())
            l.Add(New label_resource())
            l.Add(New _namespace())
            l.Add(New network())
            l.Add(New qname())
            l.Add(New reference_part())
            l.Add(New relationship())
            l.Add(New resource())
            l.Add(New sic_code())
            l.Add(New taxonomy())
            l.Add(New taxonomy_version())
            l.Add(New unit())
            l.Add(New unit_measure())
            l.Add(New uri())




            Return l
        End Get
    End Property

    Public Enum arcrole_cycles_allowed
        any = 1
        undirected = 2
        none = 3
    End Enum


    Public Enum element_balance
        debit = 1
        credit = 2
    End Enum

    Public Enum element_period_type
        instant = 1
        duration = 2
        forever = 3
    End Enum

    Public Enum unit_measure_location
        measure = 1
        numerator = 2
        denominator = 3
    End Enum

    Public Shared Sub onerror(ByRef ex As System.Exception)
        onerror(ex.Message & vbCrLf & ex.StackTrace)
    End Sub

    Public Shared Sub onerror(ByVal text As String)
        MsgBox(text)
    End Sub



    Public Enum tableNames
        accession = 1
        accession_document_association = 2
        accession_timestamp = 3
        attribute_value = 4
        context = 5
        context_aug = 6
        context_dimension = 7
        custom_arcrole_type = 8
        custom_arcrole_used_on = 9
        custom_role_type = 10
        custom_role_used_on = 11
        document = 12
        element = 13
        element_attribute_value_association = 14
        entity = 15
        enumeration_arcrole_cycles_allowed = 16
        enumeration_element_balance = 17
        enumeration_element_period_type = 18
        enumeration_unit_measure_location = 19
        fact = 20
        fact_aug = 21
        label_resource = 22
        _namespace = 23
        network = 24
        qname = 25
        reference_part = 26
        relationship = 27
        resource = 28
        sic_code = 29
        taxonomy = 30
        taxonomy_version = 31
        unit = 32
        unit_measure = 33
        uri = 34
    End Enum

    Public Shared Function executeScalar(ByVal sqlstr As String) As Object

        Dim objConnect As New NpgsqlConnection(connstr)
        objConnect.Open()
        Dim Sql As NpgsqlCommand = New NpgsqlCommand(sqlstr, objConnect)
        Dim theResult As Object = Sql.ExecuteScalar()
        Sql.Dispose()
        objConnect.Close() : objConnect.Dispose() : objConnect = Nothing
        Return theResult

    End Function

    Public Shared Function fillFromDB(ByVal sqlstr As String) As DataTable
        Dim objConnect As New NpgsqlConnection(connstr)
        objConnect.Open()
        Dim objDataAdapter As New NpgsqlDataAdapter(sqlstr, objConnect)
        Dim objDS As New DataSet()
        objDataAdapter.Fill(objDS, "data")
        objConnect.Close() : objConnect.Dispose() : objConnect = Nothing
        objDataAdapter.Dispose()
        Return objDS.Tables("data")
    End Function

    Public Shared Sub executeNonQuery(ByVal sqlstr As String)
        Dim objConnect As New NpgsqlConnection(connstr)
        objConnect.Open()
        Dim Sql As New NpgsqlCommand(sqlstr, objConnect)
        Sql.ExecuteNonQuery()
        Sql.Dispose()
        objConnect.Close() : objConnect.Dispose() : objConnect = Nothing
    End Sub


    Public Shared Function executeNonQuery(ByRef sql As NpgsqlCommand) As Integer
        Dim identity As Integer = 0
        Dim objConnect As New NpgsqlConnection(connstr)
        objConnect.Open()
        sql.Connection = objConnect
        sql.ExecuteNonQuery()

        If UCase(Mid(sql.CommandText, 1, 6)) = "INSERT" Then
            sql.Dispose()
            sql = New NpgsqlCommand("SELECT @@IDENTITY AS 'Identity'", objConnect)   ' THIS IS NOT GOING TO WORK!!!!
            identity = sql.ExecuteScalar
        End If
        sql.Dispose()
        objConnect.Close() : objConnect.Dispose() : objConnect = Nothing
        Return identity
    End Function



    Public Shared Function getColNames(ByVal tablename As String, Optional ByVal localDbase As Boolean = False) As DataTable
        Dim theData As DataTable = Nothing
        If localDbase Then
            ' theData = fillFromLocalDB("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '" & tablename & "'")
        Else
            theData = fillFromDB("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '" & tablename & "' order by ORDINAL_POSITION ASC")
        End If
        Return theData
    End Function

    Public Shared Function getInsertCommand(ByVal tablename As String, Optional ByVal localDbase As Boolean = False, Optional ByRef skipFieldsList As String() = Nothing) As String  ' remember ID MUST BE FIRST FIELD
        Dim theData As DataTable
        '   Dim foundIt As Boolean = False

        '        For Each colList In columnLists
        'If colList.TableName = tablename Then
        'theData = colList
        'foundIt = True
        'End If
        'Next



        '        If Not foundIt Then theData = fillFromDB("SELECT COLUMN_NAME FROM " & dbasename & ".INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '" & tablename & "'")
        '        If Not foundIt Then
        theData = getColNames(tablename, localDbase)
        'End If

        If skipFieldsList IsNot Nothing Then
            Dim removeRows As New List(Of DataRow)

            For Each skipField As String In skipFieldsList
                'find the row
                For Each DR As DataRow In theData.Rows

                    If DR.Item(0).ToString = skipField Then
                        removeRows.Add(DR)
                        Exit For
                    End If
                Next
            Next

            For Each DR As DataRow In removeRows
                theData.Rows.Remove(DR)
            Next
        End If


        '        Dim sqlstring As String = "INSERT INTO " & dbasename & ".." & tablename & " (" & theData.Rows(1)(0).ToString()
        Dim sqlstring As String = "INSERT INTO " & tablename & " (" & theData.Rows(1)(0).ToString()

        For i = 2 To theData.Rows.Count - 1
            sqlstring = sqlstring & ", " & theData.Rows(i)(0).ToString()
        Next

        sqlstring = sqlstring & ") VALUES (@" & theData.Rows(1)(0).ToString()

        For i = 2 To theData.Rows.Count - 1
            sqlstring = sqlstring & ", @" & theData.Rows(i)(0).ToString()
        Next
        sqlstring = sqlstring & ") "


        theData.TableName = tablename



        Return sqlstring

    End Function


    Public Shared Function getUpdateCommand(ByVal tablename As String, Optional ByVal localDbase As Boolean = False, Optional ByRef skipFieldsList As String() = Nothing) As String ' remember ID MUST BE FIRST FIELD
        Dim theData As DataTable = Nothing
        'Dim foundIt As Boolean = False

        '   For Each colList In columnLists
        'If colList.TableName = tablename Then
        'theData = colList
        'foundIt = True
        'End If
        'Next

        '        If Not foundIt Then theData = fillFromDB("SELECT COLUMN_NAME FROM " & dbasename & ".INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '" & tablename & "'")
        '        If Not foundIt Then
        theData = getColNames(tablename, localDbase)
        'End If


        Try

            If skipFieldsList IsNot Nothing Then
                For Each skipField As String In skipFieldsList
                    'find the row
                    Dim rowIndex As Integer
                    For i = 0 To theData.Rows.Count - 1
                        If theData.Rows(i)(0).ToString = skipField Then
                            rowIndex = i
                            Exit For
                        End If
                    Next
                    'remove the row
                    theData.Rows.RemoveAt(rowIndex)
                Next
            End If



            '       Dim sqlstring As String = "UPDATE " & dbasename & ".." & tablename & " SET " & theData.Rows(1)(0).ToString() & " = @" & theData.Rows(1)(0).ToString()
            Dim sqlstring As String = "UPDATE " & tablename & " SET " & theData.Rows(1)(0).ToString() & " = @" & theData.Rows(1)(0).ToString()

            For i = 2 To theData.Rows.Count - 1
                sqlstring = sqlstring & ", " & theData.Rows(i)(0).ToString() & " = @" & theData.Rows(i)(0).ToString()
            Next
            sqlstring = sqlstring & " "


            theData.TableName = tablename
            '  columnLists.Add(theData)

            Return sqlstring
        Catch ex As Exception
            onerror(ex)
            If theData IsNot Nothing Then onerror("thedata count: " & theData.Rows.Count)
            Return Nothing
        End Try

    End Function

    Public Shared Function getSelectCommand(ByVal tablename As String, Optional ByRef skipFieldsList As String() = Nothing) As String ' remember ID MUST BE FIRST FIELD
        Dim theData As DataTable


        '   If Not foundIt Then
        theData = getColNames(tablename, False)
        '   End If

        If skipFieldsList IsNot Nothing Then
            For Each skipField As String In skipFieldsList
                'find the row
                Dim rowIndex As Integer
                For i = 0 To theData.Rows.Count - 1
                    If theData.Rows(i)(0).ToString = skipField Then
                        rowIndex = i
                        Exit For
                    End If
                Next
                'remove the row
                theData.Rows.RemoveAt(rowIndex)
            Next
        End If


        Dim sqlstring As String = " FROM " & tablename & " WHERE " & theData.Rows(1)(0).ToString() & " = @" & theData.Rows(1)(0).ToString()

        For i = 2 To theData.Rows.Count - 1
            sqlstring = sqlstring & " AND " & theData.Rows(i)(0).ToString() & " = @" & theData.Rows(i)(0).ToString()
        Next
        sqlstring = sqlstring & " "


        theData.TableName = tablename
        '   columnLists.Add(theData)

        Return sqlstring
    End Function


    Public Shared Sub fillSqlCommand(ByRef sql As NpgsqlCommand, ByVal tablename As String, ByRef theObject As Object, Optional ByRef skipFieldsList As String() = Nothing) ' ByVal myType As Type)
        Dim theData As DataTable
        Dim myType As Type = theObject.GetType
        '  For Each colList In columnLists
        'If colList.TableName = tablename Then theData = colList
        'Next
        theData = getColNames(tablename, False)
        If skipFieldsList IsNot Nothing Then
            For Each skipField As String In skipFieldsList
                'find the row
                Dim rowIndex As Integer
                For i = 0 To theData.Rows.Count - 1
                    If theData.Rows(i)(0).ToString = skipField Then
                        rowIndex = i
                        Exit For
                    End If
                Next
                'remove the row
                theData.Rows.RemoveAt(rowIndex)
            Next
        End If

        Dim thetext As String = ""
        '      Try


        For i = 1 To theData.Rows.Count - 1   'skip "ID", get all of the others   
            '   carolineSettings.writeToLog(theData.Rows(i)(0).ToString() & vbCrLf & myType.GetField(theData.Rows(i)(0).ToString()).GetValue(theObject))

            '    If theData.Rows(i)(0).ToString() = "theDate" Then carolineSettings.writeToLog("FSC" & myType.GetField(theData.Rows(i)(0).ToString()).GetValue(theObject))

            sql.Parameters.AddWithValue("@" & theData.Rows(i)(0).ToString(), myType.GetField(theData.Rows(i)(0).ToString()).GetValue(theObject))
            '    thetext = thetext & theData.Rows(i)(0).ToString() & vbCrLf & myType.GetField(theData.Rows(i)(0).ToString()).GetValue(theObject)
        Next

        '        Catch
        '       End Try

    End Sub

End Class

Public Class sqlBuilder
    Public tables As New sqltables
    Public limit As Integer = 0
    Public SQLwheres As New List(Of sqlWhere)
    Public SQLfunctions As New List(Of String)
    Public DISTINCTfunctions As New List(Of String)  ' a seperate list for any distincts since they must be first!

    '  Public SQLorderBy As New List(Of String)
    ' Public SQLgroupBy As New List(Of String)
    Public orderByBox As TextBox
    Public selectBox As TextBox

    Public Function addTable(ByRef table As sqlTable, Optional ByRef joinBackTable As sqlTable = Nothing) As Boolean
        If Me.tables.Count = 0 Then
            tables.Add(table)
            Return True
        Else
            Return join(table, joinBackTable)
        End If
    End Function



    Private Function join(ByRef table As sqlTable, ByRef joinBackTable As sqlTable, Optional ByVal tableAJoinField As String = "", Optional ByVal tableBJoinField As String = "") As Boolean
        Me.tables.Add(table)
        Dim index As Integer = Me.tables.indexOf(table)
        table.joinOtherTable = joinBackTable
        If joinBackTable Is Nothing Then table.joinOtherTable = Me.tables.Item(index - 1)
        table.shortName = Chr(Asc("a") + Me.tables.indexOf(table))  ' works first 26 times.....

        If Len(tableAJoinField) = 0 Then
            'find the join fields!
            Dim ll As New List(Of String())


            For Each lt As linkTable In table.linkTables
                '     MsgBox(lt.tableName & " =  " & table.prevTable.tableName)
                If lt.tableName = table.joinOtherTable.tableName Then
                    ' a match - add to list of potential links
                    Dim s(1) As String
                    s(0) = lt.linkField
                    s(1) = lt.localField
                    ll.Add(s)
                End If
            Next



            Dim selindex As Integer = 0
            If ll.Count > 1 Then
                'prompt for choice!
                Dim mj As New joinPopUp()

                For Each s As String() In ll
                    mj.ComboBox.Items.Add(table.joinOtherTable.tableName & "." & s(0) & "  <->  " & table.tableName & "." & s(1))
                Next
                mj.ComboBox.SelectedIndex = 0

                If mj.ShowDialog = DialogResult.OK Then
                    selindex = mj.ComboBox.SelectedIndex
                Else
                    Return False
                End If

            End If

            tableAJoinField = ll.Item(selindex)(0)
            tableBJoinField = ll.Item(selindex)(1)

        End If


        table.joinOtherTableField = tableAJoinField
        table.joinLocalField = tableBJoinField
        '        MsgBox("joining on " & table.prevTable.tableName & "." & table.prevTable.joinForwardOn & " = " & table.tableName & "." & table.joinBackOn)

        Return True
    End Function


    Public Overrides Function ToString() As String
        If Me.tables.Count = 0 Then Return ""

        'Return MyBase.ToString()
        Dim str As New System.Text.StringBuilder()
        str.Append("SELECT ")

        If Len(selectBox.Text) > 0 Then
            str.Append(selectBox.Text & ", ")
        End If

        Dim firstone As Boolean = True


        Dim funcs As New List(Of String)
        funcs.AddRange(Me.DISTINCTfunctions)  ' must go first!!!
        funcs.AddRange(Me.SQLfunctions)

        For Each fs As String In funcs
            If Not firstone Then str.Append(", ")
            str.Append(fs)
            firstone = False
        Next
        str.Append(" ")

        Dim firstTable As Boolean = True

        For Each t As sqlTable In Me.tables
            For Each f As SQLfield In t.SQLselects
                If Not firstone Then str.Append(", ")
                str.Append(t.shortName & "." & f.fieldName)
                firstone = False
                firstTable = False
            Next
        Next


        If firstTable Then  ' no selects  ...add one
            '            str.Append(Me.tables.Item(0).shortName & ".*")
            str.Append("*")
        End If

        str.Append(" FROM ")

        firstone = True
        For Each t As sqlTable In Me.tables
            If Not firstone Then str.Append(" JOIN ")


            str.Append(t.tableName & " " & t.shortName)

            If Not firstone Then
                str.Append(" ON " & t.joinOtherTable.shortName & "." & t.joinOtherTableField & " = " & t.shortName & "." & t.joinLocalField)
            End If

            firstone = False
        Next

        'wheres
        firstone = True
        If Me.SQLwheres.Count > 0 Then
            str.Append(" WHERE ")
            For Each wh As sqlWhere In SQLwheres
                If Not firstone Then str.Append(" AND ")
                str.Append(wh.ToString)
                firstone = False
            Next




        End If
        str.Append(" " & orderByBox.Text)

        'limit
        If Me.limit > 0 Then str.Append(" LIMIT " & Me.limit)


        Return str.ToString

    End Function

    Function findFieldInTables(ByVal fieldname As String) As List(Of String)
        Dim l As New List(Of String)

        For Each t As sqlTable In Me.tables
            For Each f As SQLfield In t.fields
                If String.Compare(fieldname, f.fieldName, True) = 0 Then
                    l.Add(t.shortName & "." & fieldname)
                End If
            Next
        Next

        Return l
    End Function

    Public Sub New(ByRef selectBox As TextBox, ByRef orderByBox As TextBox)
        Me.selectBox = selectBox
        Me.orderByBox = orderByBox
    End Sub


End Class



Public MustInherit Class sqlTable
    Public tableName As String
    Public shortName As String = "a"
    Public joinLocalField As String
    Public joinOtherTableField As String
    Public joinOtherTable As sqlTable = Nothing
    Public fields As New SQLfields
    Public linkTables As New linkTables
    Public tableDescription As String
    Public myControl As SqlTableCntrl = Nothing
    Public SQLselects As New SQLfields
    Public parametersLists As List(Of functionParameters) = Nothing


    Dim is_selected As Boolean

    Public indentLevel As Integer = 0


    Public itemType As itemTypes = 0

    Public Enum itemTypes
        table = 0
        selectFunction = 1
        fromFunction = 2
    End Enum



    Public Sub New(ByVal name As String, Optional ByVal itemType As itemTypes = 0)
        Me.tableName = name
        Me.itemType = itemType
        fillLinkTables()

        fillFieldList()

    End Sub

    Public Overridable Sub fillLinkTables()

    End Sub

    Public Overridable Sub fillFieldList()
        '     Dim t As Type = Me.GetType

        '        For Each f As Reflection.FieldInfo In t.GetFields(Reflection.BindingFlags.Default Or Reflection.BindingFlags.DeclaredOnly)
        'Me.fields.Add(f)
        ' Next
    End Sub


    Public Property selected As Boolean
        Get
            Return is_selected
        End Get
        Set(ByVal value As Boolean)
            is_selected = value
            If myControl IsNot Nothing Then
                myControl.setSelected(value)

            End If
        End Set
    End Property


    Public Overrides Function ToString() As String
        Return tableName
    End Function


    Public Function getJoinList() As sqlTables
        Dim ls As New List(Of String)

        For Each lt As linkTable In Me.linkTables
            '    MsgBox(lt.tableName)
            If ls.IndexOf(lt.tableName) = -1 Then ls.Add(lt.tableName)
        Next

        Dim l As New sqlTables
        For Each s As String In ls
            'create the object
            If s = "namespace" Then s = "_namespace"

            Dim myType As Type = Type.GetType("XBRL." & s)
            ' MsgBox("XBRL." & s)
            Dim obj As sqlTable = Activator.CreateInstance(myType)
            l.Add(obj)
        Next






        Return l
    End Function



End Class


Public Class sqlTables
    Inherits System.Collections.CollectionBase
    '  Public Function Add() As sqlTable
    'Dim sqltable As New sqlTable
    '   List.Add(sqltable)
    '  Return sqltable
    ' End Function


   

    Public Sub Add(ByRef sqltable As sqlTable)
        List.Add(sqltable)
    End Sub

    '    Public Sub Add(ByVal tableName As String, ByVal localField As String, ByVal sqlField As String)
    '       List.Add(New sqlTable(tableName, localField, sqlField))
    '  End Sub
   

    Public Sub Remove(ByVal index As Integer)
        If index > Count - 1 Or index < 0 Then
        Else
            List.RemoveAt(index)
        End If
    End Sub

    Public Sub Remove(ByRef sqltable As sqlTable)
        List.RemoveAt(Me.List.IndexOf(sqltable))
    End Sub

    Public ReadOnly Property Item(ByVal index As Integer) As sqlTable
        Get
            If index > List.Count - 1 Then Return Nothing
            Return List.Item(index)
        End Get
    End Property

    Public ReadOnly Property ItemByID(ByVal ID As Integer) As sqlTable
        Get
            For Each itm In List
                If itm.id = ID Then
                    Return itm
                    Exit For
                End If
            Next
            Return Nothing
        End Get
    End Property

    Function indexOf(ByVal table As sqlTable) As Integer
        Return List.IndexOf(table)
    End Function

    Function lastInList() As sqlTable
        If List.Count = 0 Then Return Nothing
        Return List.Item(List.Count - 1)
    End Function

    Function selectedTable() As sqlTable
        For Each t As sqlTable In Me.List
            If t.selected Then Return t
        Next

        Return Nothing
    End Function

    Public Sub addAt(ByVal index As Integer, ByRef sqlTable As sqlTable)
        List.Insert(index, sqlTable)
    End Sub
End Class


Public Class sqlWhere
    Public text As String
    Public andOr As Boolean = True ' true = and, false = or

    Public Sub New(ByVal text As String)
        Me.text = text

    End Sub


    Public Overrides Function ToString() As String
        Return text
    End Function

End Class

Public Class linkTable
    Public tableName As String
    Public localField As String
    Public linkField As String


    Public Sub New()
    End Sub
    Public Sub New(ByVal localField As String, ByVal tableName As String, ByVal linkField As String)
        Me.tableName = tableName
        Me.localField = localField
        Me.linkField = linkField
    End Sub

End Class

Public Class linkTables
    Inherits System.Collections.CollectionBase
    Public Function Add() As linkTable
        Dim linktable As New linkTable
        List.Add(linktable)
        Return linktable
    End Function

    Public Sub Add(ByRef linktable As linkTable)
        List.Add(linktable)
    End Sub

    Public Sub Add(ByVal localField As String, ByVal tableName As String, ByVal linkField As String)
        List.Add(New linkTable(localField, tableName, linkField))
    End Sub



    Public Sub Remove(ByVal index As Integer)
        If index > Count - 1 Or index < 0 Then
        Else
            List.RemoveAt(index)
        End If
    End Sub

    Public Sub Remove(ByRef linktable As linkTable)
        List.RemoveAt(Me.List.IndexOf(linktable))
    End Sub

    Public ReadOnly Property Item(ByVal index As Integer) As linkTable
        Get
            Return CType(List.Item(index), linkTable)
        End Get
    End Property

    Public ReadOnly Property ItemByID(ByVal ID As Integer) As linkTable
        Get
            For Each itm In List
                If itm.id = ID Then
                    Return itm
                    Exit For
                End If
            Next
            Return Nothing
        End Get
    End Property
End Class


Public Class SQLfield
    Public fieldName As String
    Public description As String
    Public fieldType As Type

    Public Sub New(ByVal fname As String, ByVal description As String, ByVal ftype As Type)
        Me.fieldName = fname
        Me.description = description
        Me.fieldType = ftype
    End Sub


    Public Overrides Function ToString() As String
        Return fieldName
    End Function

End Class


Public Class SQLfields
    Inherits System.Collections.CollectionBase
  

    Public Sub Add(ByRef SQLfield As SQLfield)
        List.Add(SQLfield)
    End Sub

    Public Sub Add(ByVal fname As String, ByVal description As String, ByRef objecttype As System.Type)

        Dim fname2 As String = fname
        If fname = "namespace" Then fname2 = "_namespace"
        Dim finfo As Type = objecttype.GetField(fname2).FieldType

        List.Add(New SQLfield(fname, description, finfo))
    End Sub



    Public Sub Remove(ByVal index As Integer)
        If index > Count - 1 Or index < 0 Then
        Else
            List.RemoveAt(index)
        End If
    End Sub

    Public Sub Remove(ByRef SQLfield As SQLfield)
        List.RemoveAt(Me.List.IndexOf(SQLfield))
    End Sub

    Public ReadOnly Property Item(ByVal index As Integer) As SQLfield
        Get
            Return CType(List.Item(index), SQLfield)
        End Get
    End Property

    Public ReadOnly Property ItemByID(ByVal ID As Integer) As SQLfield
        Get
            For Each itm In List
                If itm.id = ID Then
                    Return itm
                    Exit For
                End If
            Next
            Return Nothing
        End Get
    End Property
End Class


